package com.goldfish666.remote_control.pojo;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.goldfish666.remote_control.enums.ResultCodeEnum;
import lombok.*;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.util.function.Consumer;
import java.util.function.Supplier;

@Data
@NoArgsConstructor
@Slf4j
public class Result<T> implements Serializable {
    private ResultCodeEnum status;
    private String msg;
    private T data;
    @JsonIgnore
    @Getter(AccessLevel.PRIVATE)
    @Setter(AccessLevel.PRIVATE)
    private boolean hasSuccess;
    @JsonIgnore
    @Getter(AccessLevel.PRIVATE)
    @Setter(AccessLevel.PRIVATE)
    private boolean hasFail;
    @JsonIgnore
    @Getter(AccessLevel.PRIVATE)
    @Setter(AccessLevel.PRIVATE)
    private boolean hasFinals;
    @JsonIgnore
    @Getter(AccessLevel.PRIVATE)
    @Setter(AccessLevel.PRIVATE)
    private boolean hasThrow;
    @Builder
    public Result(ResultCodeEnum status, T data, String msg) {
        this.status = status;
        this.data = data;
        this.msg = msg;
    }

    public static Result buildErrorResult(String message) {
        return buildErrorResult(message, ResultCodeEnum.Error);
    }

    public static Result buildErrorResult(String message, ResultCodeEnum code) {
        return Result.builder()
                .msg(message)
                .status(code)
                .build();
    }

    /**
     * 是否执行成功
     *
     * @return 是否成功
     */
    @JsonIgnore
    public Boolean isSuccess() {
        return status == null;
    }

    public Result<T> ifSuccess(Consumer<T> consumer) {
        if (hasSuccess) {
            return this;
        }
        hasSuccess = true;
        if (isSuccess()) {
            consumer.accept(data);
        }
        return this;
    }

    public Result<T> ifFail(Consumer<Result<T>> consumer) {
        if (hasFail) {
            return this;
        }
        hasFail = true;
        if (!isSuccess()) {
            consumer.accept(this);
        }
        return this;
    }

    public Result finals(Consumer<Result<T>> consumer) {
        if (hasFinals) {
            return this;
        }
        hasFinals = true;
        consumer.accept(this);
        return this;
    }

    public <X extends Throwable> Result<T> orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (hasThrow) {
            return this;
        }
        hasThrow = true;
        if (isSuccess()) {
            return this;
        }
        throw exceptionSupplier.get();
    }

}
